﻿using System;
using System.Collections.Generic;
using System.Timers;
using Model01.Exceptions;
using Model01.Modifier;
using Model01.Objects;
using Model01.Transportation;

namespace Model01.Management
{
    public class Manager
    {
        #region Fields

        /// <summary>
        /// Time delay of timer (more than 15 and less then 95).
        /// </summary>
        private static TimesRepaint timeRepaint = TimesRepaint.Normal;

        /// <summary>
        /// Max speed determined by law
        /// </summary>
        private static double maxSpeed;

        /// <summary>
        /// Timers are slow. If you would use this coefficient, you can solve this problem
        /// </summary>
        private static double accelerateCoefficient;

        /// <summary>
        /// = model_unit_of_length / meter. Default = 0.1.
        /// </summary>
        private static double lengthCoefficient = 0.1;

        /// <summary>
        /// = model_unit_of_time / milisecond. Default = 1.
        /// </summary>
        private static double timeCoefficient = 1.0;

        public static double g = Manager.ModelAcseleration(10);

        private static Timer timer = new Timer((int)timeRepaint);

        #endregion

        #region Methods

        public static void Start()
        {
            timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
            timer.Start();
        }

        static void timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            OnPaint(new object(), new EventArgs());
        }

        /// <summary>
        /// Returns input length value in model units of length.
        /// </summary>
        /// <param name="length">Length value in meters.</param>
        /// <returns></returns>
        //[Obsolete("It's useless method", true)]
        public static int ModelLength(double length)
        {
            return (int)(length / lengthCoefficient);
        }

        /// <summary>
        /// Returns how much model units of time in input length value.
        /// </summary>
        /// <param name="length">Time value in miliseconds.</param>
        /// <returns></returns>
        [Obsolete("It's useless method", true)]
        public static double ModelTime(double time)
        {
            return timeCoefficient * time;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="acseleration">in m/s</param>
        /// <returns></returns>
        public static double ModelAcseleration(double acseleration)
        {
            return timeCoefficient * timeCoefficient / lengthCoefficient * acseleration;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="speed">Speed in km per h.</param>
        /// <returns></returns>
        public static double ModelSpeed(double speed)
        {
            return timeCoefficient / lengthCoefficient * speed / 3.6;
        }

        /// <summary>
        /// Calculate accelerateCoefficient depending on (10 less then timeRepaint less then 100)
        /// </summary>
        public static void Init()
        {
            double maxTimes = 1000.0 / (double)timeRepaint;
            double realTimes = 1.0;
            switch (timeRepaint)
            {
                case TimesRepaint.MostFast: realTimes = 65.0; break;
                case TimesRepaint.Fast: realTimes = 31.0; break;
                case TimesRepaint.Quick: realTimes = 21.0; break;
                case TimesRepaint.Normal: realTimes = 16.0; break;
                case TimesRepaint.Slow: realTimes = 12.0; break;
                case TimesRepaint.MostSlow: realTimes = 10.0; break;
            }
            accelerateCoefficient = maxTimes / realTimes;
        }

        #endregion

        #region Events

        public static event EventHandler OnPaint = delegate { };

        #endregion        

        #region Properties

        /// <summary>
        /// Gets or sets Model01.Management.TimesRepaint time interval between model updates.
        /// </summary>
        public static TimesRepaint TimeRepaint
        {
            get { return Manager.timeRepaint; }
            set { Manager.timeRepaint = value; }
        }        

        /// <summary>
        /// Gets or sets max speed determined by law in km per hour.
        /// </summary>
        public static double MaxSpeed
        {
            get { return Manager.maxSpeed; }
            set 
            {
                if (value > 0)
                    maxSpeed = Manager.timeCoefficient / Manager.lengthCoefficient * value / 3.6;
                else
                    throw new NonPositiveValueException();
            }
        }        

        /// <summary>
        /// Timers are slow. If you would use this coefficient, you can solve this problem
        /// </summary>
        public static double AccelerateCoefficient
        {
            get { return Manager.accelerateCoefficient; }
        }        

        /// <summary>
        /// Gets or sets value of the ratio model_unit_of_length / meter.
        /// </summary>
        public static double LengthCoefficient
        {
            get { return Manager.lengthCoefficient; }
            set { Manager.lengthCoefficient = value; }
        }
                                
        /// <summary>
        /// Gets or sets value of the ratio model_unit_of_time / milisecond.
        /// </summary>
        public static double TimeCoefficient
        {
            get { return Manager.timeCoefficient; }
            set { Manager.timeCoefficient = value; }
        }

        #endregion

        public static List<CityCar> cars;
        public static List<Streetlight> streetlights;
        public static bool ind = false;
    }

    public enum TimesRepaint
    {
        MostFast = 15,
        Fast = 31,
        Quick = 46,
        Normal = 62,
        Slow = 77,
        MostSlow = 93
    }
}